package msghandler

import (
	"fmt"
	"reflect"
	"sync"

	"gitee.com/night-tc/gobige/common"
	"gitee.com/night-tc/gobige/logger"
	"gitee.com/night-tc/gobige/msgdef"
	"gitee.com/night-tc/gobige/safecontainer"
)

/*
	MsgHandler 作为底层通讯层与上层应用层之间逻辑传递的桥梁
*/

// IMsgHandler 消息处理器接口，定义了消息处理的核心方法
type IMsgHandler interface {
	// DoMsg 处理所有缓冲的消息
	DoMsg()
	// DoNormalMsg 处理普通消息
	DoNormalMsg(name string, content msgdef.IMsg) error
	// DoRPCMsg 处理RPC消息
	DoRPCMsg(methodName string, content msgdef.IMsg) error
	// DoSrvMsg 处理Srv消息
	DoSrvMsg(name string, req, msg msgdef.IMsg)
	// FireMsg 触发普通消息，保证不被挂起
	FireMsg(name string, content msgdef.IMsg)
	// FireRPC 触发RPC消息，保证不被挂起
	FireRPC(method string, content msgdef.IMsg)
	// FireSrv 触发Srv消息，保证不被挂起
	FireSrv(name string, req, msg msgdef.IMsg)
	// RegMsgProc 注册消息处理对象
	RegMsgProc(proc interface{})
	// RegMsgOwner 注册消息拥有者
	RegMsgOwner(IMsgOwner)
	// GetMsgOwner 获取消息拥有者
	GetMsgOwner() IMsgOwner
	// GetCallChan 获取有消息时的chan
	GetCallChan() chan bool
	// SetMainHander 设置父级消息路由器
	SetMainHander(msghandler IMsgHandler)

	getMsgList() *safecontainer.SafeListT[*msgFireInfo]
	getRpcList() *safecontainer.SafeListT[*rpcFireInfo]
	getSrvList() *safecontainer.SafeListT[*srvFireInfo]
	fireMsg(msg *msgFireInfo)
	fireRPC(msg *rpcFireInfo)
	fireSrv(msg *srvFireInfo)
}

// NewMsgHandler 创建一个新的消息处理器
func NewMsgHandler() *MsgHandler {

	return &MsgHandler{
		msgFireInfo:  safecontainer.NewSafeListT[*msgFireInfo](),
		rpcFireInfo:  safecontainer.NewSafeListT[*rpcFireInfo](),
		srvFireInfo:  safecontainer.NewSafeListT[*srvFireInfo](),
		defaultFuncs: make([]reflect.Value, 0, 10),
		msgChan:      make(chan bool, 1),
	}
}

// msgFireInfo 触发一个事件时必须的信息
type msgFireInfo struct {
	handler IMsgHandler // 触发该消息的处理器
	name    string      // 消息名称
	content msgdef.IMsg // 消息内容
}

// GetHandler 获取消息处理器
func (msg *msgFireInfo) GetHandler() IMsgHandler {
	return msg.handler
}

// rpcFireInfo RPC消息触发信息
type rpcFireInfo struct {
	handler    IMsgHandler // 触发该RPC的处理器
	methodName string      // 方法名
	content    msgdef.IMsg // 消息内容
}

// GetHandler 获取RPC消息处理器
func (rpc *rpcFireInfo) GetHandler() IMsgHandler {
	return rpc.handler
}

// srvFireInfo Srv消息触发信息
type srvFireInfo struct {
	handler    IMsgHandler // 触发该Srv的处理器
	methodName string      // 方法名
	req, msg   msgdef.IMsg // req路由消息，msg具体消息
}

// GetHandler 获取Srv消息处理器
func (this *srvFireInfo) GetHandler() IMsgHandler {
	return this.handler
}

// MsgHandler 消息处理中心，负责消息的注册、分发和执行
type MsgHandler struct {
	msgFuncs sync.Map // MsgProc_前缀 的所有方法
	rpcFuncs sync.Map // RPC_前缀     的所有方法
	srvFuncs sync.Map // Srv_前缀     的服务器之间的调用需要回复

	defaultFuncs []reflect.Value // 默认消息处理函数

	msgFireInfo *safecontainer.SafeListT[*msgFireInfo] // MsgProc_ 消息队列
	rpcFireInfo *safecontainer.SafeListT[*rpcFireInfo] // RPC_ 消息队列
	srvFireInfo *safecontainer.SafeListT[*srvFireInfo] // Srv_ 消息队列

	MsgOwner IMsgOwner // 消息拥有者

	msgChan chan bool // 消息通知通道

	/*
		mainHander 如果多个msghandlers 共用一个协程的时候，会有一个主MsgHandlers
		这样的话，就可以把所有消息放到这个主MsgHandlers里
	*/
	mainHander IMsgHandler
}

// 获取子处理器
func (this *MsgHandler) GetNewSubHandler() (result *MsgHandler) {
	result = NewMsgHandler()
	result.SetMainHander(this)
	return result
}

// 注册消息拥有者
func (this *MsgHandler) RegMsgOwner(owner IMsgOwner) {
	this.MsgOwner = owner
}

func (this *MsgHandler) GetMsgOwner() IMsgOwner {
	return this.MsgOwner
}

func (this *MsgHandler) getMsgList() *safecontainer.SafeListT[*msgFireInfo] {
	return this.msgFireInfo
}
func (this *MsgHandler) getRpcList() *safecontainer.SafeListT[*rpcFireInfo] {
	return this.rpcFireInfo
}

func (this *MsgHandler) getSrvList() *safecontainer.SafeListT[*srvFireInfo] {
	return this.srvFireInfo
}

// RegMsg
// RegMsgProc 注册消息处理对象
// 其中 proc 是一个对象，包含是类似于 MsgProc_XXXXX的一系列函数，分别用来处理不同的消息
func (this *MsgHandler) RegMsgProc(proc interface{}) {

	v := reflect.ValueOf(proc)
	t := reflect.TypeOf(proc)

	for i := 0; i < t.NumMethod(); i++ {
		methodName := t.Method(i).Name

		//MsgProc前缀的所有方法
		msgName, msgHandler, err := GetPreFunc(MSG_PREFIX, methodName, v.MethodByName(methodName))
		if err == nil {
			SetHandlerFunc(&this.msgFuncs, msgName, msgHandler)
			continue
		}

		// 判断是否是RPC处理函数
		msgName, msgHandler, err = GetPreFunc(RPC_PREFIX, methodName, v.MethodByName(methodName))
		if err == nil {
			SetHandlerFunc(&this.rpcFuncs, msgName, msgHandler)
			continue
		}
		// 判断是否是Srv处理函数
		msgName, msgHandler, err = GetPreFunc(SRV_PREFIX, methodName, v.MethodByName(methodName))
		if err == nil {
			SetHandlerFunc(&this.srvFuncs, msgName, msgHandler)
			continue
		}
	}

	this.addDefaultFunc(proc)
}

func (this *MsgHandler) addDefaultFunc(proc interface{}) {

	v := reflect.ValueOf(proc)
	var defaultFunc = v.MethodByName("MsgProc_DefaultMsgHandler")
	if defaultFunc.IsValid() {
		this.defaultFuncs = append(this.defaultFuncs, defaultFunc)
	}
}

// SetMainHander 设置父级消息路由器
func (this *MsgHandler) SetMainHander(msghandler IMsgHandler) {
	if msghandler != nil {
		this.mainHander = msghandler
		this.msgChan = msghandler.GetCallChan()
	}
}

// 获取有消息的信号量
func (this *MsgHandler) GetCallChan() chan bool {
	return this.msgChan
}

// FireMsg 触发消息, 保证不被挂起
func (this *MsgHandler) FireMsg(name string, content msgdef.IMsg) {
	if this == nil {
		return
	}
	msg := &msgFireInfo{
		handler: this,
		name:    name,
		content: content,
	}
	this.fireMsg(msg)
	select {
	case this.msgChan <- true:
	default:
	}
}

// 这里会牵扯到级联判断的问题，这样修改可以支持
func (this *MsgHandler) fireMsg(msg *msgFireInfo) {
	if this.mainHander != nil {
		this.mainHander.fireMsg(msg)
	} else {
		this.msgFireInfo.Put(msg)
	}
}

// FireRPC 触发消息, 保证不被挂起
func (this *MsgHandler) FireRPC(method string, content msgdef.IMsg) {
	msg := &rpcFireInfo{
		handler:    this,
		methodName: method,
		content:    content,
	}
	this.fireRPC(msg)
	select {
	case this.msgChan <- true:
	default:
	}
}

// 这里会牵扯到级联判断的问题，这样修改可以支持
func (this *MsgHandler) fireRPC(msg *rpcFireInfo) {
	if this.mainHander != nil {
		this.mainHander.fireRPC(msg)
	} else {
		this.rpcFireInfo.Put(msg)
	}
}

// FireSrv 触发Srv_前缀的函数,保证不被挂起
func (this *MsgHandler) FireSrv(name string, req, msg msgdef.IMsg) {
	srvmsg := &srvFireInfo{
		handler:    this,
		methodName: name,
		req:        req,
		msg:        msg,
	}
	this.fireSrv(srvmsg)
	select {
	case this.msgChan <- true:
	default:
	}
}

// 这里会牵扯到级联判断的问题，这样修改可以支持
func (this *MsgHandler) fireSrv(msg *srvFireInfo) {
	if this.mainHander != nil {
		this.mainHander.fireSrv(msg)
	} else {
		this.srvFireInfo.Put(msg)
	}
}

// DoMsg 将缓冲的消息一次性处理
func (this *MsgHandler) DoMsg() {

	var procName string
	var info interface{}
	var err error
	var msgh IMsgHandler
	defer func() {
		if GetRecover() {
			if err := recover(); err != nil {
				logger.Error(err, procName)
				buf := common.StackTrace()
				common.OnRecover(err, buf, info)
				if msgh != nil && msgh.GetMsgOwner() != nil {
					msgh.GetMsgOwner().OnPanic(common.GetError(err))
				}
			}
		}
	}()

	for {
		info, err = this.msgFireInfo.Pop()
		if err != nil {
			break
		}
		msginfo := info.(*msgFireInfo)
		procName = msginfo.name
		msgh = msginfo.GetHandler()
		e := msginfo.handler.DoNormalMsg(msginfo.name, msginfo.content)
		if e != nil {
			logger.Error(e)
		}
	}

	for {
		info, err = this.rpcFireInfo.Pop()
		if err != nil {
			break
		}
		rpcinfo := info.(*rpcFireInfo)
		procName = rpcinfo.methodName
		msgh = rpcinfo.GetHandler()
		e := rpcinfo.handler.DoRPCMsg(rpcinfo.methodName, rpcinfo.content)
		if e != nil {
			logger.Error(e)
		}
	}

	for {
		info, err = this.srvFireInfo.Pop()
		if err != nil {
			break
		}
		msginfo := info.(*srvFireInfo)
		procName = msginfo.methodName
		msgh = msginfo.GetHandler()
		msginfo.handler.DoSrvMsg(msginfo.methodName, msginfo.req, msginfo.msg)

	}
}

// DoNormalMsg 立即触发普通消息
func (this *MsgHandler) DoNormalMsg(name string, content msgdef.IMsg) error {
	if this.MsgOwner != nil {
		this.MsgOwner.OnMsgBefore(name, content)
		defer this.MsgOwner.OnMsged(name, content)
	}

	ifuncs, ok := this.msgFuncs.Load(name)
	if !ok {
		if len(this.defaultFuncs) == 0 {
			//如果是心跳，没有处理就没有处理，不做error输出
			if name == "HeartBeat" {
				return nil
			}
			return fmt.Errorf("Cant find handler %s", name)
		}

		for _, f := range this.defaultFuncs {
			if f.IsValid() {
				f.Call([]reflect.Value{reflect.ValueOf(content)})
			}
		}

		return nil
	}

	for _, msgFunc := range ifuncs.([]reflect.Value) {
		msgFunc.Call([]reflect.Value{reflect.ValueOf(content)})
	}

	return nil
}

// DoRPCMsg 立即触发RPC消息
func (this *MsgHandler) DoRPCMsg(methodName string, content msgdef.IMsg) error {
	if this.MsgOwner != nil {
		this.MsgOwner.OnRpcBefore(methodName, content)
		defer this.MsgOwner.OnRpced(methodName, content)
	}
	ifuncs, ok := this.rpcFuncs.Load(methodName)
	if !ok {
		return fmt.Errorf("Method %v can't find", methodName)
	}

	funcs, _ := ifuncs.([]reflect.Value)
	for _, rpcFunc := range funcs {
		outVal := rpcFunc.Call([]reflect.Value{reflect.ValueOf(content)})
		//如果有通用错误处理回调,则处理返回值 传递给通用错误处理
		if this.MsgOwner != nil &&
			len(outVal) > 0 && outVal[0].CanInterface() {
			var msg msgdef.IMsg = content

			if err, ok := outVal[0].Interface().(error); ok && err != nil {
				this.MsgOwner.OnRpcReturn(msg, err)
			} else if outVal[0].Interface() == nil {
				this.MsgOwner.OnRpcReturn(msg, nil)
			}
		}
	}

	return nil
}

// DoSrvMsg 调用Srv_前缀的函数
func (this *MsgHandler) DoSrvMsg(name string, req, msg msgdef.IMsg) {
	ifuncs, ok := this.srvFuncs.Load(name)
	if !ok {
		logger.Warnf("DoSrvMsg.Method %s Can't Find", name)
		return
	}
	args := []reflect.Value{reflect.ValueOf(req), reflect.ValueOf(msg)}
	for _, msgFunc := range ifuncs.([]reflect.Value) {
		outVal := msgFunc.Call(args)
		//如果有通用错误处理回调,则处理返回值 传递给通用错误处理
		if this.MsgOwner != nil &&
			len(outVal) > 0 && outVal[0].CanInterface() {
			//process with error
			if err, ok := outVal[0].Interface().(error); ok && err != nil {
				this.MsgOwner.OnSrvReturn(req, msg, err)
			} else if outVal[0].Interface() == nil {
				this.MsgOwner.OnSrvReturn(req, msg, nil)
			}
		}
	}
}
